<template>
    <el-drawer v-model="visible" :title="title" :size="size" :direction="direction" :modal="modal"
        :modal-class="modalClass" :append-to-body="appendToBody" :lock-scroll="lockScroll" :custom-class="customClass"
        :open-delay="openDelay" :close-delay="closeDelay" :close-on-click-modal="closeOnClickModal"
        :close-on-press-escape="closeOnPressEscape" :show-close="showClose" :before-close="handleBeforeClose"
        :destroy-on-close="destroyOnClose" @open="handleOpen" @opened="handleOpened" @close="handleClose"
        @closed="handleClosed">
        <!-- 自定义标题 -->
        <template v-if="$slots.title" #header>
            <slot name="title" />
        </template>

        <!-- 主要内容 -->
        <div class="drawer-content">
            <!-- 详情展示内容 -->
            <div v-if="type === 'detail'" class="detail-content">
                <div v-if="detailConfig" class="detail-list">
                    <div v-for="(item, index) in detailConfig" :key="index" class="detail-item"
                        :class="{ 'detail-group': item.type === 'group' }">
                        <!-- 分组标题 -->
                        <div v-if="item.type === 'group'" class="group-title">
                            {{ item.label }}
                        </div>
                        <!-- 普通字段 -->
                        <template v-else>
                            <div class="field-label">{{ item.label }}</div>
                            <div class="field-value">
                                <!-- 自定义渲染 -->
                                <slot v-if="item.slot" :name="item.slot" :value="getValue(item.prop)" :item="item"
                                    :data="data" />
                                <!-- 标签类型 -->
                                <el-tag v-else-if="item.type === 'tag'"
                                    :type="getTagType(getValue(item.prop), item.tagMap)"
                                    :size="item.tagSize || 'default'">
                                    {{ getTagText(getValue(item.prop), item.tagMap) }}
                                </el-tag>
                                <!-- 图片类型 -->
                                <el-image v-else-if="item.type === 'image'" :src="getValue(item.prop)"
                                    :style="{ width: item.imageWidth || '80px', height: item.imageHeight || '80px' }"
                                    :preview-src-list="[getValue(item.prop)]" fit="cover" />
                                <!-- 链接类型 -->
                                <el-link v-else-if="item.type === 'link'" :type="item.linkType || 'primary'"
                                    :href="getValue(item.prop)" target="_blank">
                                    {{ getValue(item.prop) }}
                                </el-link>
                                <!-- 日期类型 -->
                                <span v-else-if="item.type === 'date'">
                                    {{ formatDate(getValue(item.prop), item.format) }}
                                </span>
                                <!-- 金额类型 -->
                                <span v-else-if="item.type === 'money'" class="money-value">
                                    ¥{{ formatMoney(getValue(item.prop)) }}
                                </span>
                                <!-- 默认文本 -->
                                <span v-else>{{ getValue(item.prop) || '-' }}</span>
                            </div>
                        </template>
                    </div>
                </div>
                <slot v-else name="detail" :data="data" />
            </div>

            <!-- 表单编辑内容 -->
            <div v-else-if="type === 'form'" class="form-content">
                <DynamicForm v-if="formConfig" ref="formRef" v-model="formData" :config="formConfig"
                    :label-width="formLabelWidth" :label-position="formLabelPosition" :size="formSize"
                    :show-buttons="false" @submit="handleFormSubmit" />
                <slot v-else name="form" :form-data="formData" />
            </div>

            <!-- 自定义内容 -->
            <div v-else class="custom-content">
                <slot :data="data" />
            </div>
        </div>

        <!-- 底部操作按钮 -->
        <template v-if="showFooter" #footer>
            <div class="drawer-footer">
                <slot name="footer" :loading="loading" :confirm="handleConfirm" :cancel="handleCancel">
                    <el-button v-if="showCancelButton" @click="handleCancel">
                        {{ cancelButtonText }}
                    </el-button>
                    <el-button v-if="showConfirmButton" type="primary" :loading="loading" @click="handleConfirm">
                        {{ confirmButtonText }}
                    </el-button>
                </slot>
            </div>
        </template>
    </el-drawer>
</template>

<script setup lang="ts">
/**
 * 抽屉组件
 * @author Wu.Liang
 * @description 支持详情查看、快速操作等抽屉功能
 */
import { ref, computed, watch } from 'vue'
import { ElMessage } from 'element-plus'
import DynamicForm from './DynamicForm.vue'
import type { FormItemConfig } from './DynamicForm.vue'
import { formatDate as utilFormatDate, formatMoney as utilFormatMoney } from '@/utils'
import { showSuccess, showError, showWarning, showInfo } from '@/utils/message'

interface DetailFieldConfig {
    // 字段属性名
    prop?: string
    // 标签文本
    label: string
    // 字段类型
    type?: 'text' | 'tag' | 'image' | 'link' | 'date' | 'money' | 'group'
    // 自定义渲染插槽
    slot?: string
    // 标签映射（tag类型）
    tagMap?: Record<string, { text: string; type: string }>
    tagSize?: 'large' | 'default' | 'small'
    // 图片尺寸（image类型）
    imageWidth?: string
    imageHeight?: string
    // 链接类型（link类型）
    linkType?: 'primary' | 'success' | 'warning' | 'danger' | 'info'
    // 日期格式（date类型）
    format?: string
}

interface Props {
    // 是否显示
    modelValue: boolean
    // 抽屉标题
    title?: string
    // 抽屉类型
    type?: 'custom' | 'detail' | 'form'
    // 抽屉尺寸
    size?: string | number
    // 打开方向
    direction?: 'ltr' | 'rtl' | 'ttb' | 'btt'
    // 是否显示遮罩
    modal?: boolean
    // 遮罩样式类
    modalClass?: string
    // 是否插入到body
    appendToBody?: boolean
    // 是否锁定滚动
    lockScroll?: boolean
    // 自定义样式类
    customClass?: string
    // 打开延时
    openDelay?: number
    // 关闭延时
    closeDelay?: number
    // 点击遮罩是否关闭
    closeOnClickModal?: boolean
    // 按ESC是否关闭
    closeOnPressEscape?: boolean
    // 是否显示关闭按钮
    showClose?: boolean
    // 关闭时销毁
    destroyOnClose?: boolean

    // 详情配置
    detailConfig?: DetailFieldConfig[]

    // 表单相关
    formConfig?: FormItemConfig[]
    formData?: Record<string, any>
    formLabelWidth?: string
    formLabelPosition?: 'left' | 'right' | 'top'
    formSize?: 'large' | 'default' | 'small'

    // 底部按钮
    showFooter?: boolean
    showConfirmButton?: boolean
    showCancelButton?: boolean
    confirmButtonText?: string
    cancelButtonText?: string

    // 加载状态
    loading?: boolean

    // 关闭前回调
    beforeClose?: (done: () => void) => void

    // 传递数据
    data?: any
}

const props = withDefaults(defineProps<Props>(), {
    type: 'custom',
    size: '50%',
    direction: 'rtl',
    modal: true,
    appendToBody: false,
    lockScroll: true,
    openDelay: 0,
    closeDelay: 0,
    closeOnClickModal: true,
    closeOnPressEscape: true,
    showClose: true,
    destroyOnClose: false,
    formLabelWidth: '100px',
    formLabelPosition: 'right',
    formSize: 'default',
    showFooter: false,
    showConfirmButton: true,
    showCancelButton: true,
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    loading: false
})

const emit = defineEmits<{
    'update:modelValue': [visible: boolean]
    'confirm': [data?: any]
    'cancel': []
    'open': []
    'opened': []
    'close': []
    'closed': []
}>()

const formRef = ref()
const formData = ref<Record<string, any>>({})

// 计算属性
const visible = computed({
    get: () => props.modelValue,
    set: (value) => emit('update:modelValue', value)
})

// 监听表单数据变化
watch(() => props.formData, (newValue) => {
    if (newValue) {
        formData.value = { ...newValue }
    }
}, { immediate: true, deep: true })

// 工具函数
const getValue = (prop?: string) => {
    if (!prop || !props.data) return ''
    return prop.split('.').reduce((obj, key) => obj?.[key], props.data)
}

const getTagType = (value: any, tagMap?: Record<string, { text: string; type: string }>) => {
    if (!tagMap || !tagMap[value]) return 'info'
    return tagMap[value].type
}

const getTagText = (value: any, tagMap?: Record<string, { text: string; type: string }>) => {
    if (!tagMap || !tagMap[value]) return value
    return tagMap[value].text
}

const formatDate = (date: any, format?: string) => {
    if (!date) return '-'
    return utilFormatDate(date, format || 'YYYY-MM-DD HH:mm:ss')
}

const formatMoney = (amount: any) => {
    if (!amount && amount !== 0) return '0.00'
    return utilFormatMoney(amount)
}

// 事件处理
const handleOpen = () => {
    emit('open')
}

const handleOpened = () => {
    emit('opened')
}

const handleClose = () => {
    emit('close')
}

const handleClosed = () => {
    // 重置表单数据
    if (props.type === 'form') {
        formData.value = {}
    }
    emit('closed')
}

const handleBeforeClose = (done: () => void) => {
    if (props.beforeClose) {
        props.beforeClose(done)
    } else {
        done()
    }
}

const handleConfirm = async() => {
    if (props.type === 'form') {
        // 表单验证
        if (formRef.value) {
            try {
                await formRef.value.validate()
                emit('confirm', formData.value)
            } catch (error) {
                showWarning('请检查表单填写是否正确')
                return
            }
        } else {
            emit('confirm', formData.value)
        }
    } else {
        emit('confirm', props.data)
    }
}

const handleCancel = () => {
    emit('cancel')
    visible.value = false
}

const handleFormSubmit = (data: Record<string, any>) => {
    emit('confirm', data)
}

// 暴露方法
const validate = () => {
    return formRef.value?.validate()
}

const resetFields = () => {
    formRef.value?.resetFields()
}

const clearValidate = () => {
    formRef.value?.clearValidate()
}

defineExpose({
    validate,
    resetFields,
    clearValidate
})
</script>

<style lang="scss" scoped>
.drawer-content {
    height: 100%;
    display: flex;
    flex-direction: column;

    .detail-content {
        flex: 1;

        .detail-list {
            .detail-item {
                padding: 12px 0;
                border-bottom: 1px solid var(--el-border-color-lighter);

                &:last-child {
                    border-bottom: none;
                }

                &.detail-group {
                    padding: 20px 0 8px;

                    .group-title {
                        font-size: 16px;
                        font-weight: 600;
                        color: var(--el-text-color-primary);
                        border-bottom: 1px solid var(--el-border-color-light);
                        padding-bottom: 8px;
                    }
                }

                &:not(.detail-group) {
                    display: flex;
                    align-items: flex-start;

                    .field-label {
                        width: 120px;
                        flex-shrink: 0;
                        color: var(--el-text-color-secondary);
                        font-size: 14px;
                        line-height: 22px;
                    }

                    .field-value {
                        flex: 1;
                        color: var(--el-text-color-primary);
                        font-size: 14px;
                        line-height: 22px;
                        word-break: break-all;

                        .money-value {
                            color: var(--el-color-danger);
                            font-weight: 600;
                        }
                    }
                }
            }
        }
    }

    .form-content {
        flex: 1;
        padding: 10px 0;
    }

    .custom-content {
        flex: 1;
    }
}

.drawer-footer {
    display: flex;
    justify-content: flex-end;
    gap: 12px;
    padding: 16px 0;
    border-top: 1px solid var(--el-border-color-lighter);
}
</style>

<style lang="scss">
// 全局样式覆盖
.el-drawer {
    .el-drawer__header {
        padding: 16px 20px;
        border-bottom: 1px solid var(--el-border-color-lighter);
        margin-bottom: 0;

        .el-drawer__title {
            font-size: 16px;
            font-weight: 600;
        }
    }

    .el-drawer__body {
        padding: 20px;
        overflow-y: auto;
    }

    .el-drawer__footer {
        padding: 0 20px 20px;
    }
}
</style>
